/*********************************************************************************************
	Fichier: SDLFonctions.c
	Ensemble des fonctions nécessaires pour pouvoir jouer au tetris. Interface graphique.
**********************************************************************************************/
#include "SDLFonctions.h"
#include <SDL/SDL_mixer.h>

SDL_Surface* ecran = NULL; /* stockage de la surface de l'écran */
SDL_Surface* blocs[10] = {NULL}; /* stockage de la surface des 10 blocs */
SDL_Surface* fond = NULL; /* Le stockage de la surface du fond */
SDL_Surface* fondmenu = NULL; /* stockage de la surface du fondmenu */
SDL_Surface* fondpause = NULL; /* stockage de la surface du fondpause */
SDL_Surface* fondperdu = NULL; /* stockage de la surface du fondperdu */
TTF_Font *police = NULL; /* Stockage des informations de police */
SDL_Color couleurNoire, couleurBlanche;

void SDL_INIT()
{
	extern SDL_Surface* ecran; /*surface qui correspond a toute la fenetre, le pointeur va stocker la surface de l'écran  (SDL alloue de l'espace en memoire pour cette surface)*/
	extern SDL_Surface* blocs[10]; /*pointeurs qui vont stocker 10 surfaces blocs */
	extern SDL_Surface *fond, *fondmenu, *fondperdu; /*! pointeur qui va stocker la surface du fond (1 pour le fond du jeu, 1 pour le fon du menu, 1 pour le fond de perdu)*/
	extern TTF_Font* police;
    extern SDL_Color couleurNoire, couleurBlanche;

    /* Charge les images Bitmap qui correspondent a des blocs, chaque bloc ayant une couleur differente, d'où le chargement de 10 images */
	blocs[VIDE] = SDL_LoadBMP("bin/image/cube-vide.bmp");
	SDL_SetColorKey(blocs[VIDE], SDL_SRCCOLORKEY, SDL_MapRGB(blocs[VIDE]->format, 0,52,102));

	blocs[SUCETTE] = SDL_LoadBMP("bin/image/cube-sucette.bmp");
	SDL_SetColorKey(blocs[SUCETTE], SDL_SRCCOLORKEY, SDL_MapRGB(blocs[SUCETTE]->format, 0,52,102));

	blocs[TAGADA] = SDL_LoadBMP("bin/image/cube-tagada.bmp");
	SDL_SetColorKey(blocs[TAGADA], SDL_SRCCOLORKEY, SDL_MapRGB(blocs[TAGADA]->format, 0,52,102));

	blocs[GATEAU] = SDL_LoadBMP("bin/image/cube-gateau.bmp");
	SDL_SetColorKey(blocs[GATEAU], SDL_SRCCOLORKEY, SDL_MapRGB(blocs[GATEAU]->format, 0,52,102));

	blocs[COOKIE] = SDL_LoadBMP("bin/image/cube-cookie.bmp");
	SDL_SetColorKey(blocs[COOKIE], SDL_SRCCOLORKEY, SDL_MapRGB(blocs[COOKIE]->format, 0,52,102));

	blocs[FRAISE] = SDL_LoadBMP("bin/image/cube-fraise.bmp");
	SDL_SetColorKey(blocs[FRAISE], SDL_SRCCOLORKEY, SDL_MapRGB(blocs[FRAISE]->format, 0,52,102));

	blocs[NYAN] = SDL_LoadBMP("bin/image/cube-nyan.bmp");
	SDL_SetColorKey(blocs[NYAN], SDL_SRCCOLORKEY, SDL_MapRGB(blocs[NYAN]->format, 0,52,102));
	
	blocs[CUPCAKE] = SDL_LoadBMP("bin/image/cube-cupcake.bmp");
	SDL_SetColorKey(blocs[CUPCAKE], SDL_SRCCOLORKEY, SDL_MapRGB(blocs[CUPCAKE]->format, 0,52,102));

	blocs[BONBON] = SDL_LoadBMP("bin/image/cube-bonbon.bmp");
	SDL_SetColorKey(blocs[BONBON], SDL_SRCCOLORKEY, SDL_MapRGB(blocs[BONBON]->format, 0,52,102));

	blocs[ETOILE] = SDL_LoadBMP("bin/image/cube-etoile.bmp");
	SDL_SetColorKey(blocs[ETOILE], SDL_SRCCOLORKEY, SDL_MapRGB(blocs[ETOILE]->format, 0,52,102));
	
	fond = SDL_LoadBMP("bin/image/fond.bmp"); /* Chargement d'une image Bitmap dans une surface qui correspondra a notre fond de jeu Nyan cat fly!*/
	fondmenu = SDL_LoadBMP("bin/image/fondmenu.bmp");/* Chargement d'une image Bitmap dans une surface qui correspondra a notre fond menu*/
	fondpause = SDL_LoadBMP("bin/image/fondpause.bmp");/* Chargement d'une image Bitmap dans une surface qui correspondra a notre fond de pause*/
	fondperdu = SDL_LoadBMP("bin/image/fondperdu.bmp");/* Chargement d'une image Bitmap dans une surface qui correspondra a notre fond de fin de partie*/

    couleurNoire.r = couleurNoire.g = couleurNoire.b = 0; /* on définit la couleur noire (0,0,0) */
    couleurBlanche.r = couleurBlanche.g = couleurBlanche.b  = 255; /*! on définit la couleur blanche (255,255,255) */

	SDL_Init(SDL_INIT_VIDEO); /* Démarrage de la SDL (ici : chargement du système vidéo)*/
	TTF_Init();/* sert à démarrer le module SDL qui gère les textes*/
	police = TTF_OpenFont("bin/fonts/comic.ttf", 30); /* mets dans 'police' ( de type TTF_Font*) la fonte comic.ttf*/

  
	ecran = SDL_SetVideoMode(1024, 668, 32,SDL_HWSURFACE | SDL_DOUBLEBUF); 
	//Cela ouvre une fenêtre de taille 1024*668 en 32 bits/pixel avec des options (double buffering, données chargées dans mémoire vidéo);


	SDL_WM_SetCaption("LE_TETRIS_CLONE:NYAN_CAT_FLY!", NULL); /* titre que l'on donne à la fenetre */
}

void SDLAfficherFond()
{
	SDL_Rect positionFond; /* definie une aire de rectangle,il va garder les positions dans l'ecran */
    positionFond.x = 0; /* position de positionFond en 0 sur l'axe des abcisses */
    positionFond.y = 0; /* position de postionFond en 0 sur l'axe des ordonnées */
	extern SDL_Surface* ecran; /* pointeur qui va stocker la surface ecran */
	extern SDL_Surface* fond; /* pointeur qui va stocker la surface fond */
	SDL_BlitSurface(fond, NULL, ecran, &positionFond); /*! collage du fond NYAN CAT FLY sur l'ecran */
}

void SDLAfficherTerrain(Terrain * t)
{
	int i;
	int j;
	for ( j = 0 ; j < TAILLE_Y ; j++) /*on parcours le terrain */
	{
		for ( i = 0 ; i < TAILLE_X ; i++)
		{
			if ((t->ter[i][j] != NULL))
			{
			    SDLAfficherBloc(i, j, t->ter[i][j]->couleur); /*on affiche le bloc sur la case (i,j) avec sa couleur appropriée (= t->ter[i][j]->couleur c'est la couleur de la piece occupant la case (i,j))*/
			}
        }
	}
}

void SDLAfficherPiece(Piece * p)
{
	int i,j;
	for ( i = 0 ; i < MAX_TAILLE_PIECE_X ; i++ ) /* on parcours la piece */
		for ( j = 0 ; j < MAX_TAILLE_PIECE_Y ; j++ )
		{
			if ((p->forme[i][j]) == 1 && (p->posYpiece + i > 0))
			{
				SDLAfficherBloc(p->posXpiece + j, p->posYpiece + i , p->couleur); /* a chaque fois qu'on rencontre un 1 on affiche un bloc a la bonne position ce qui nous affichera une piece a la fin*/
			}
		}

}

void SDLAfficherBloc(int x, int y, Couleur c)
{
	extern SDL_Surface* ecran;
	extern SDL_Surface* blocs[10];

	SDL_Rect bloc; /*on crée le point d'ancrage pour l'image que l'on veut afficher*/
    bloc.x = PositionTerrainX + x * TailleBlocX;
    bloc.y = PositionTerrainY + y * TailleBlocY;

	SDL_BlitSurface(blocs[c], NULL, ecran, &bloc); /* collage du bloc ayant la couleur c sur l'ecran */

}

void SDLAfficherSuivante(Piece * p)
{

	extern SDL_Surface* ecran;
	extern SDL_Surface* blocs[10];
	SDL_Rect bloc; /* on crée le point d'ancrage pour l'image que l'on veut afficher*/

	int i,j;
	for ( i = 0 ; i < MAX_TAILLE_PIECE_X ; i++ ) /*on parcours la piece */
		for ( j = 0 ; j < MAX_TAILLE_PIECE_Y ; j++ )
		{
			bloc.x = positionSuivanteX + i * TailleBlocX; /* coordonnees x du bloc */
			bloc.y = positionSuivanteY + j * TailleBlocY; /* coordonnes y du bloc */
			if ((p->forme[i][j]) == 1)
			{
				SDL_BlitSurface(blocs[p->couleur], NULL, ecran, &bloc); /* collage du bloc avec la couleur adaptee sur l'ecran */
			}
		}
}

void SDL_REFRESH(void)
{
	extern SDL_Surface* ecran;
	SDL_Flip(ecran); /*Mise à jour de l'écran*/
	SDL_Delay(10); /* permet de mettre en pause le programme pendant 10 millisecondes, sinon ca irait trop vite */
}

void SDL_STOP()
{
	extern SDL_Surface* ecran;
	extern SDL_Surface* blocs[10];
	extern SDL_Surface* fond, *fondmenu, *fondpause, *fondperdu;
	extern TTF_Font *police;

	int i;
	for ( i = 0 ; i < 10 ; i++) /* On fait une boucle pour bien libérer les 10 blocs */
	{
	    SDL_FreeSurface(blocs[i]); /* liberation de la surface bloc[i]*/
	}
	SDL_FreeSurface(fond); /*liberation de la surface fond */
	SDL_FreeSurface(fondmenu); /* liberation de la surface fondmenu */
	SDL_FreeSurface(fondpause); /* liberation de la surface fondpause */
	SDL_FreeSurface(fondperdu); /* liberation de la surface fondperdu */
	SDL_FreeSurface(ecran);/*liberation de la surface ecran */
	TTF_CloseFont(police);/*liberation de la surface fond */
	TTF_Quit(); /*arrête SDL_ttf */
	SDL_Quit();/*arrêt de la SDL (libération de la mémoire).*/
}


void SDLDeplacerPiece(Jeu * j)
{
	SDL_Event event; /* Cette variable servira plus tard à gérer les évènements */
	Uint32 temps_courant;

	temps_courant = SDL_GetTicks();

	while ( JeuGetEtat(j) == JEU )
	{
		while (SDL_PollEvent(&event)) /* on vide la liste des évenemnts */
        	{
            switch(event.type)
            {
                case SDL_QUIT: JeuSetEtat(j, QUIT);
                    break;
                case SDL_KEYDOWN:
                    switch(event.key.keysym.sym)
                    {
                        case SDLK_DOWN: while (JeuActionClavier(j, 'b')){SDLAfficherJeu(j);}return ; /*la fleche du bas, la piece descend d'un coup */
                            break;
                        case SDLK_RIGHT: JeuActionClavier(j, 'd');  /* la fleche droite on deplace la piece a droite  */
                            break;
                        case SDLK_LEFT: JeuActionClavier(j, 'g'); /* la fleche gauche on deplace la piece  a gauche  */
                            break;
                             break;
                        case SDLK_UP: JeuActionClavier(j, 'p');  /*la fleche du haut on fait une rotation de la piece  */
                            break;
                             break;
                        case SDLK_ESCAPE: JeuSetEtat(j, QUIT); /* la touche Echap du clavier, permet de quitter le jeu */
                            break;
                        case SDLK_PAUSE: JeuSetEtat(j, PAUSE); /* la touche Pause du clavier (en haut a droite), met le jeu sur pause */
                            break;
                        default:
                            break;
                    }
                    break;
                default:
                    break;
            }
        }

        /* permet de faire tomber la pièce toute seule, plus le niveau est haut plus la pièce descendra vite */
        if ( SDL_GetTicks() - temps_courant < (1200 / j->niveau + 1)  && SDL_GetTicks() - temps_courant > (800/ j->niveau + 1)) /*! quand i modulo en fonction du niveau vaut 0 on fait tomber la piece d'un cran*/
        {
		temps_courant = SDL_GetTicks();
            if ( ! JeuActionClavier(j, 'b') ){return;} /* Si la personne n'a pas appuyé sur bas , on continue a faire descendre la piece automatiquement*/
        }
        SDLAfficherJeu(j);
	}
}

void SDL_EcrireScore(int score)
{
	extern TTF_Font *police;
	extern SDL_Surface *ecran;

	extern SDL_Color couleurNoire, couleurBlanche;

	SDL_Surface * SDL_texte;
	SDL_Rect position;
		position.x = positionScoreX;
		position.y = positionScoreY;
	char texte[20] = "";
	sprintf(texte, "%d", score);
	SDL_texte = TTF_RenderText_Shaded(police, texte, couleurNoire, couleurBlanche);
	SDL_SetColorKey(SDL_texte, SDL_SRCCOLORKEY, SDL_MapRGB(SDL_texte->format, 255, 255, 255));
	SDL_BlitSurface(SDL_texte, NULL, ecran, &position);
	SDL_FreeSurface(SDL_texte);
}

void SDL_EcrireNiveau(int niveau)
{
	extern TTF_Font *police;
	extern SDL_Surface *ecran;

	extern SDL_Color couleurNoire, couleurBlanche;


	SDL_Surface * SDL_texte;
	SDL_Rect position;
		position.x = positionNiveauX;
		position.y = positionNiveauY;
	char texte[20] = "";
	sprintf(texte, "  %d", niveau);
	SDL_texte = TTF_RenderText_Shaded(police, texte, couleurNoire,couleurBlanche);
	SDL_SetColorKey(SDL_texte, SDL_SRCCOLORKEY, SDL_MapRGB(SDL_texte->format, 255, 255, 255));
	SDL_BlitSurface(SDL_texte, NULL, ecran, &position);
	SDL_FreeSurface(SDL_texte);

}


void SDLAfficherJeu(Jeu * j)
{
    /* suivant l'état de la partie on affiche le bon fond */
	switch (JeuGetEtat(j) )
	{
		case MENU: SDLMENU(j);
			break;
		case JEU: SDLJEU(j);
			break;
		case PAUSE: SDLPAUSE(j);
			break;
		case PERDU: SDLPERDU(j);
			break;
		case QUIT:
			break;
		default: break;
	}

}

void SDLJEU(Jeu * j)
{
	SDLAfficherFond();
	SDL_EcrireScore(JeuGetScore(j));
	SDLAfficherTerrain(JeuGetTerrain(j));
	SDLAfficherSuivante(JeuGetSuivante(j));
	SDL_EcrireNiveau(JeuGetNiveau(j));
	SDL_REFRESH(); /* mise a jour de l'ecran */
}


void SDLPAUSE(Jeu * j)
{
	SDL_Rect positionFond; /* definie une aire de rectangle,il va garder les positions dans l'ecran */
	positionFond.x = 0; /* position de positionFond en 0 sur l'axe des abcisses */
	positionFond.y = 0; /* position de postionFond en 0 sur l'axe des ordonnées */
	extern SDL_Surface* ecran;
	extern SDL_Surface* fondpause;
	SDL_BlitSurface(fondpause, NULL, ecran, &positionFond); /* collage du fond de pause sur l'ecran */
	SDL_Event event; /* Cette variable servira plus tard à gérer les évènements */

	SDL_REFRESH(); /* mise a jour de l'ecran */

	do
	{
		SDL_WaitEvent(&event); /* la variable event contient obligatoirement un évènement */
		switch(event.type)
		{
			case SDL_KEYDOWN:
			switch(event.key.keysym.sym)
			{
				case SDLK_ESCAPE: JeuSetEtat(j, QUIT); /* si on appuie sur Echap on quitte le jeu */
					break;

				case SDLK_RETURN: JeuSetEtat(j, JEU); /* Si on appuie sur entrée on reprend le jeu la ou on en était */
					break;
				default:
					break;
			}
			break;
		case SDL_QUIT: JeuSetEtat(j, QUIT);
			break;
		default:
			break;
		}
	}
	while ( JeuGetEtat(j) == PAUSE );


}

void SDLMENU(Jeu * j)
{
	SDL_Rect positionFond; /* definie une aire de rectangle, il va garder les positions dans l'ecran */
	positionFond.x = 0; /* position de positionFond en 0 sur l'axe des abcisses */
	positionFond.y = 0; /* position de postionFond en 0 sur l'axe des ordonnées */
	extern SDL_Surface* ecran;
	extern SDL_Surface* fondmenu;
	SDL_BlitSurface(fondmenu, NULL, ecran, &positionFond); /* collage du fond de Menu sur l'ecran */
	SDL_Event event; /* Cette variable servira plus tard à gérer les évènements */

	SDL_REFRESH(); /* mise a jour de l'ecran */

	do
	{
		SDL_WaitEvent(&event); /* la variable event contient obligatoirement un évènement .*/
		switch(event.type)
		{
			case SDL_KEYDOWN:
			switch(event.key.keysym.sym)
			{
				case SDLK_ESCAPE: JeuSetEtat(j, QUIT); /*si on appuie sur Echap on quitte le jeu */
					break;

				case SDLK_RETURN: JeuSetEtat(j, JEU); /*si on appuie sur Entrée on attaque une partie */
					break;
				default:
					break;
			}
			break;
		case SDL_QUIT: JeuSetEtat(j, QUIT);
			break;
		default:
			break;
		}
	}
	while ( JeuGetEtat(j) == MENU );
}

void SDLPERDU(Jeu * j)
{
	SDL_Rect positionFond; /*definie une aire de rectangle, il va garder les positions dans l'ecran */
	positionFond.x = 0; /* position de positionFond en 0 sur l'axe des abcisses */
	positionFond.y = 0; /* position de postionFond en 0 sur l'axe des ordonnées */
	extern SDL_Surface* ecran;
	extern SDL_Surface* fondperdu;
	SDL_BlitSurface(fondperdu, NULL, ecran, &positionFond); /*collage du fond Perdu sur l'ecran */
	SDL_Event event; /*Cette variable servira plus tard à gérer les évènements */

	SDL_REFRESH(); /* mise a jour de l'ecran */

	do
	{
		SDL_WaitEvent(&event); /* la variable event contient obligatoirement un évènement . */
		switch(event.type)
		{
			case SDL_KEYDOWN:
			switch(event.key.keysym.sym)
			{
				case SDLK_ESCAPE: JeuSetEtat(j, QUIT); /* si on appuie sur Echap on quitte le jeu */
					break;
				case SDLK_RETURN: JeuRelancer(j); /* si on appuie sur Entrée on attaque une nouvelle partie */
					break;
				default:
					break;
			}
			break;
		case SDL_QUIT: JeuSetEtat(j, QUIT);
			break;
		default:
			break;
		}
	}
	while ( JeuGetEtat(j) == PERDU );

}

void SDLDelais(void)
{
	SDL_Delay(300); /* permet de mettre en pause le programme pendant 100 millisecondes,sinon ca irait trop vite */
}

int main(int argc, char *argv[])
{
	SDL_INIT(); /* on démare la SDL */
	Jeu * j = JeuCreer(); /* création de la partie */
	JeuInitialiser(j); /*on initialise j */
	Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, 1024); /* on initialise le son */

	SDL_WM_SetCaption("LE_TETRIS_CLONE:NYAN_CAT_FLY!", NULL);
	Mix_Music *musique;

	musique = Mix_LoadMUS("bin/musique/Nyan_Cat.mp3");
	Mix_PlayMusic(musique, -1);

	do
	{
		while ( JeuGetEtat(j) < PERDU ) /* tant qu'on doit boucler */
		{
			SDLAfficherJeu(j);
			JeuNouvellePiece(j);
			SDLDeplacerPiece(j);
			while ( JeuEffacerLignesPleine(j) == 1) /* tant qu'on a des lignes pleines à effacer */
			{
				SDLDelais();
				while ( JeuFaireTomberToutesPieces(j) == 1 ) /* tant qu'on arrive à faire tomber des pieces */
				{
					SDLDelais();
					SDLAfficherJeu(j); /* on rafraichit l'ecran */
				}
			}
		}

		SDLAfficherJeu(j);
	}
	while (JeuGetEtat(j) != QUIT);/* tant que l'etat du jeu est différent de QUIT */

	JeuDetruire(j); /* on a crée donc on détruit */
	SDL_STOP(); /* libère toutes les variables SDL */
	Mix_FreeMusic(musique);
	Mix_CloseAudio(); /* on ferme le son */
	return EXIT_SUCCESS; /* fermeture du programme */
}
